package com.pactera.asmp.server.job.dispatch.impl.perform;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.pactera.asmp.server.common.constants.*;
import com.pactera.asmp.server.common.logprint.utils.CollectionUtils;
import com.pactera.asmp.server.common.websocket.WebSocketServerDevice;
import com.pactera.asmp.server.entity.Subtask;
import com.pactera.asmp.server.entity.TaskDTO;
import com.pactera.asmp.server.entity.TaskDevice;
import com.pactera.asmp.server.job.dispatch.BaseDispatchBus;
import com.pactera.asmp.server.job.dispatch.impl.AsmpTaskDispatchBus;
import com.pactera.asmp.server.job.dispatch.impl.BaseManager;
import com.pactera.asmp.server.job.dispatch.IDeviceEvent;
import com.pactera.asmp.server.job.dispatch.ITaskEvent;
import com.pactera.asmp.server.job.dispatch.impl.feedback.FeedbackManager;
import com.pactera.asmp.server.pojo.ScriptInfo2;
import com.pactera.asmp.server.pojo.SocketMessage;
import com.pactera.asmp.server.pojo.WSScriptMessage;
import com.pactera.asmp.server.service.ScriptInfoServcieImpl;
import com.pactera.asmp.server.vo.StartupTestVo;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.Session;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class PerformManager extends BaseManager {

    @Autowired
    private WebSocketServerDevice wssd;

    @Autowired
    private ScriptInfoServcieImpl mScriptInfoServcieImpl;

    @Autowired
    private PerformRepository repository;

    @Override
    protected BaseDispatchBus initDispatcher() {
        return AsmpTaskDispatchBus.getDispatchBus();
    }

    @Override
    public void deviceEventHandler(IDeviceEvent event) {

    }

    @Override
    public void taskHandler(ITaskEvent event) {
        if (event.getType().equals(TaskEventType.SUBTASK_DISPATCH)) {
            //网络发送子任务
            handleSubtaskDispatch(event);
        }
        if (event.getType().equals(TaskEventType.SUBTASK_DEVICE_CLEAR)) {
            //网络取消任务
            handleSubtaskCancelForDevice(event);
        }
    }

    //设备取消任务事件处理
    private void handleSubtaskCancelForDevice(ITaskEvent event){
        Subtask subtask = JSONObject.parseObject(event.getData(),Subtask.class);
        Session session = getSessionMap().get(subtask.getDuid());
        WSScriptMessage<String> msgContent = new WSScriptMessage<>();
        msgContent.setTouuid(subtask.getDuid());
        msgContent.setFromuuid("server");
        msgContent.setMsgcode("204");  // 取消正在执行的任务
        List<Integer> taskIds = new ArrayList<>();
        taskIds.add(subtask.getId().intValue());
        msgContent.setTaskIds(taskIds);
        SocketMessage message = new SocketMessage("server",subtask.getDuid(), "json", msgContent.toString().getBytes(StandardCharsets.UTF_8), null);
        if(session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(new String(message.getData(), StandardCharsets.UTF_8));
                subtask.setTaskStatus(SubTaskStatus.FAIL_CANCEL_SEND.getValue());
                repository.modifySubtask(subtask);
            } catch (IOException e) {
                log.error("session Dispatch  ", e);
                this.retry(event);
                return;
            }
            TaskDTO task = repository.getTaskById(subtask.getTaskId().intValue());
            if(task.getStatus().equals(TaskStatus.TASK_CANCEL.getValue())) {
                sendTaskEvent(task, TaskEventType.TASK_COMPLETE, event);
                //任务取消
                log.info("task cancel,taskId={}",task.getId());
                return ;
            }
            List<TaskDevice> list = repository.getTaskDeviceListByDuid(subtask.getDuid());
            if (CollectionUtils.isEmpty(list)) {
                log.info("handleSubtaskCancelForDevice not found taskDevice,duid={}", subtask.getDuid());
                return;
            }
            TaskDevice td = list.get(0);
            sleep(1000L);
            sendTaskDeviceEvent(td, DeviceEventType.DEVICE_FREE, event);
        }
    }

    //分发事件处理
    private void handleSubtaskDispatch(ITaskEvent event){
        Subtask subtask = JSONObject.parseObject(event.getData(),Subtask.class);
        List<TaskDevice> taskDeviceList = repository.getTaskDeviceListByDuid(subtask.getDuid());
        if(CollectionUtils.isEmpty(taskDeviceList)){
            log.info("无占用设备！duid:{}", subtask.getDuid());
            return;
        }
        TaskDTO task = repository.getTaskById(subtask.getTaskId().intValue());
        TaskDevice td = taskDeviceList.get(0);
        //build message
        Short performanceType = null;
        List<String> scriptStringList = new ArrayList<>();
        WSScriptMessage<String> msgContent = new WSScriptMessage<>();
        msgContent.setTouuid(subtask.getDuid());
        msgContent.setFromuuid("server");
        msgContent.setMsgcode("203");
        msgContent.setTaskId(subtask.getId().intValue());
        msgContent.setExeNumber(1);
        msgContent.setAuxDuid(td.getAuxDuid());
        msgContent.setMonkeyExeNumber(subtask.getMonkeyExeNumber());
        //msgContent.setColdHotStartActivity(task.getColdHotStartActivity());
        if(StringUtils.isNotEmpty(task.getColdHotStartActivity()) && task.getType() == 4){
            List stList = JSONObject.parseObject(task.getColdHotStartActivity(),  List.class);
            for(Object json:stList){
                StartupTestVo startupTestVo = JSONObject.parseObject(json.toString(), StartupTestVo.class);
                startupTestVo.setTestTimes(startupTestVo.getTestTimes()*task.getExeNumber());
                msgContent.getStartupTestList().add(startupTestVo);
            }
            msgContent.setColdHotStartType(task.getColdHotStartType());
            msgContent.setColdHotStartMode(task.getColdHotStartMode());
            msgContent.setIntervalTime(task.getIntervalTime());
            performanceType = 1;
            msgContent.setExeNumber(task.getExeNumber());
        }

        if(StringUtils.isNotEmpty(subtask.getScriptIds()) && task.getType() != 4) {
            String[] scrptIdArray = subtask.getScriptIds().split(",");
            List<Integer> scrptIdList = Arrays.stream(scrptIdArray).map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());
            List<ScriptInfo2> scriptInfos = mScriptInfoServcieImpl.selectScriptByScriptIds(scrptIdList);
            //保持执行顺序一致
            HashMap<Integer, ScriptInfo2> smap = new HashMap<>();
            for(ScriptInfo2 s:scriptInfos){
                smap.put(s.getId(), s);
            }
            for(Integer key: scrptIdList){
                scriptStringList.add(JSONObject.toJSONString(smap.get(key)));
            }
            performanceType = scriptInfos.get(0).getPerformanceType();
            msgContent.setList(scriptStringList);
        }else if(StringUtils.isNotEmpty(subtask.getPackages())) {
            msgContent.setList(Lists.newArrayList(subtask.getPackages().split(",")));
        }
        if(null != task) {
            msgContent.setErrorVideoType(task.getErrorVideoType());
            msgContent.setTaskType(task.getType());
        }
        msgContent.setPerformanceType(performanceType);
        log.info("分发事件处理: {}", subtask.getDuid());
        SocketMessage message = new SocketMessage("server",subtask.getDuid(), "json", msgContent.toString().getBytes(StandardCharsets.UTF_8), null);
        Session session = getSessionMap().get(subtask.getDuid());
        if(session != null && session.isOpen()) {
            try {
                log.info("sendText: {}", JSONObject.toJSONString(message));
                session.getBasicRemote().sendText(new String(message.getData(), StandardCharsets.UTF_8));
            } catch (IOException e) {
                log.error("session Dispatch  ", e);
                return;
            }
            sendTaskEvent(subtask, TaskEventType.SUBTASK_SEND, event);
        }else{
            //更新状态到待分发状态
            subtask.setTaskStatus(SubTaskStatus.CREATE.getValue());
            boolean rslt = repository.modifySubtask(subtask);
            if(!rslt){
                //重试
                this.retry(event);
            }
        }

    }

    private Map<String, Session> getSessionMap(){
        HashMap<String, Session> map = new HashMap<>();
        for (String sessionKey : WebSocketServerDevice.id2sessionMap.keySet()) {
            String duid = sessionKey.split("@")[0];
            map.put(duid, WebSocketServerDevice.id2sessionMap.get(sessionKey));
        }
        return map;
    }

    @Override
    public String getBussinessType() {
        return PerformManager.class.getSimpleName();
    }

}
